home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / pnuc1 < prev    next >
Text File  |  1999-02-21  |  28KB  |  1,103 lines

  1. \ Objects, constants, values etc.
  2.  
  3. forward    INTERPRET        \ Not a vector any more - we never used that feature
  4. forward    REFILL
  5. forward    FREFILL
  6. forward    THROW
  7.  
  8.  
  9. false        value        RAinMod        \ Set if a relocatable address is in a module
  10. false        value        echo?        \ Set if we're echoing during first stage load
  11.  
  12. false        value        err_info_valid?
  13.  
  14.  
  15.             variable    #TIB
  16.             variable    >IN
  17.  
  18. 0            value        LATEST
  19. 0            value        CURR-DEF
  20. 0            value        FENCE
  21. 0            value        SRC-START
  22. 0            value        SRC-LEN
  23. 0            value        SOURCE-ID
  24.  
  25. 0            value        ACTW
  26.  
  27. 0            value        OUT
  28. 0            value        #lines_read
  29. 0            value        STATE
  30. false        value        CSTATE
  31. 10            value        BASE
  32. -1            value        DPL
  33. 0            value        HLD
  34. false        value        CASE_IN_NAMES?
  35.  
  36. 0            value        throwHandler
  37. big#        value        DotStkLim
  38. -1            value        SLEEPTICKS
  39. 5            constant    PROCESSOR        \ let's call PowerPC processor 5
  40. true        constant    AppleEvents?    \ AppleEvents are always available on PPC
  41. true        constant    GestaltAvail?    \ Likewise for Gestalt
  42.  
  43. \ The following values are used internally by Mops.
  44.  
  45. 0            value        CD_gpr#
  46. 0            value        TO_gpr#
  47. 0            value        const_data_start
  48. 0            value        CD_GPR_loc
  49.  
  50. 0            value        savedRP
  51. 0            value        MMRgn
  52.  
  53. 0            value        meth_seg#
  54.  
  55.  
  56. $ BFFBFFBF ,                        \ marker so we can easily recognize the 
  57.                                     \  execution buffer
  58.                                     
  59.             variable    exBuff        512 allot        \ the buffer
  60.             
  61. $ 98765432 ,                        \ marker so we can recognize the end
  62.  
  63. 0            value        exBuff_offs
  64. false        value        MRopen?
  65. false        value        initzed?
  66. 0            value        quitapp?
  67.  
  68. 0            value        frNxtDP
  69. 0            value        (err#)
  70. 0            value        loc#
  71. 0            value        #P
  72. 0            value        #PL
  73. 0            value        #FP
  74. 0            value        #FPL
  75. 0            value        #VL
  76.  
  77. 0            value        tempObj_block_size    \ if nonzero, this is the size of the extra
  78.                                             \  part of the return stack frame, used for
  79.                                             \  temp objects.
  80.  
  81. false        value        tempObjs?    \ true if we have temp objects.  We can't rely on
  82.                                     \  tempObj_block_size being nonzero, since they
  83.                                     \  might all be in registers.
  84.                                             
  85. 0            value        releaseTemps_xt
  86. 0            value        fltflg
  87. 0            value        local?
  88. 0            value        localSect?
  89. 0            value        method?
  90. 0            value        ^meth_link
  91. 0            value        selfref?
  92. 0            value        objclass
  93. 0            value        #1st
  94. 0            value        #last
  95. 0            value        heldMod
  96. 0            value        heldModStart
  97. \ 0            value        heldModBase
  98. 0            value        methindex
  99. false        value        sacomp?
  100. true        value        relocchk?
  101. false        value        inhibitmb?
  102. 0            value        sups2skip
  103. false        value        savingdic?
  104.  
  105.  
  106. BL            constant    BL
  107. 8            constant    #THREADS
  108. big#        constant    BIG#
  109. -300        constant    FILE-MARK
  110.  
  111. \ Some handler code values that we need to be able to access from
  112. \ above the nucleus:
  113.  
  114. classCode    constant    CLASSCODE
  115. objcode        constant    OBJCODE
  116. FvalCode    constant    FVALCODE
  117.  
  118. true        value        CURS?
  119. true        value        UCFLAG
  120. inlMk        constant    INLMK
  121.  
  122. 0            value        currBase
  123. 0            value        colAflg
  124.  
  125.             variable    tempVbl        16  allot
  126.  
  127.  
  128. \                    ==============================
  129. \                               SYSTEM VECTORS
  130. \                    ==============================
  131.  
  132. (*
  133.     ['] (emit)        -> emitvec
  134.     ['] (cr)        -> crvec
  135.     ['] (type)        -> typevec
  136.     ['] (spaces)    -> spvec
  137.     ['] (emit)        -> echovec
  138.     ['] (sf)        -> setfWind
  139. \    0                -> quitvec        \ mh May94 - quit doesn't get changed any more
  140.     ['] bye            -> byevec
  141. *)
  142.  
  143. ' null        sVect        HEADER
  144.  
  145. : rtnFalse    0  ;
  146.  
  147. ' null        sVect        LOGVEC
  148.  
  149. \ ' rtnFalse    sVect        UFIND
  150.  
  151.     dynamicVect            EXTRAFIND
  152.  
  153. \ ' null        sVect        NUMACCUMULATE
  154.  
  155.  
  156. ' null        sVect        PAUSE
  157. ' null        sVect        ?PAUSE
  158. ' null        sVect        GETSPACE
  159. ' null        sVect        RNGERR
  160. ' null        sVect        $ERR
  161. ' null        sVect        ARITHERR
  162. \ ' null    sVect        EXTRA_INITS
  163. ' null        sVect        ERRORVEC
  164. ' null        sVect        QUITVEC
  165. ' null        sVect        ABORTVEC
  166. ' null        sVect        SETFWIND
  167. \ ' null        sVect        DIE
  168. \ ' null        sVect        DFLT-DIE
  169. \ ' null        sVect        FREFILL
  170. ' null        sVect        MODLOAD
  171. \ ' null        sVect        TEIDLE
  172. ' null        sVect        COMPINLINE
  173. \ ' null        sVect        INTERPRET
  174.  
  175. ' null        sVect        OPENAPPVEC
  176. ' null        sVect        OPENDOCVEC
  177. ' null        sVect        PRINTDOCVEC
  178. ' null        sVect        QUITAPPVEC
  179. ' null        sVect        READ1DOCVEC
  180. ' null        vect        TEidle_vect
  181. \ ' null        vect        codeGen_vect
  182.  
  183.  
  184. \    ========= dummy words used for accessing locals (see zArgs) =========
  185.  
  186. $ BC0D    dummy_op    LOCPARM
  187. $ BC25    dummy_op    FLOCPARM
  188.  
  189.  
  190. \    ======== Dictionary header address conversion ========
  191.  
  192. : ?DP  ;
  193.  
  194.  
  195. \ TRAVERSE converts an addr pointing to one end of the name field
  196. \  to one pointing to the other.
  197.  
  198. : TRAVERSE { addr dirn \ cnt  -- addr' }
  199.     32 -> cnt
  200.     dirn 0>=
  201.     IF                        \ going up
  202.         addr c@  $ 1F and
  203.         4+ -4 and  1-  ++> addr
  204.     ELSE                    \ going down
  205.         BEGIN
  206.             1 --> addr
  207.             addr c@x 0< IF  addr EXIT drop THEN
  208.             1 --> cnt
  209.             cnt
  210.         NUNTIL
  211.     THEN
  212.     addr
  213. ;
  214.  
  215.  
  216. : N>LINK    4-  ;
  217. : L>NAME    4+  ;
  218. : NAME>        1 traverse  3+  ;
  219. : LINK>        L>name name> ;
  220.  
  221. \ >BODY ( xt -- dfa )  has to go to the data area for variables, values
  222. \  etc.  This isn't (and can't ever be) standard, since these kinds of
  223. \  words don't have an 'xt' under the standard.  But in Mops, you can
  224. \  tick them, and use >BODY on the result to get to the data.
  225.  
  226. : >BODY        2+ @abs  ;
  227. : >NAME        3-  -1 traverse  ;
  228. : >LINK        >name  n>link  ;
  229. : >HDLR        2-  ;
  230.  
  231.  
  232. \                    ==============================
  233. \                            STACK MANIPULATION
  234. \                    ==============================
  235.  
  236.  
  237. $ BD0F    $ 6200    special_op  DUP
  238. $ BD0F    $ 6300    special_op  2DUP
  239. $ BD0F    $ 6400    special_op  DROP
  240. $ BD0F    $ 6500    special_op  2DROP
  241. $ BD0F    $ 6600    special_op  SWAP
  242. $ BD0F    $ 6700    special_op  OVER
  243. $ BD0F    $ 6800    special_op  NIP
  244. $ BD0F    $ 6900    special_op  TUCK
  245. $ BD0F    $ 6A00    special_op  ROT
  246. $ BD0F    $ 6B00    special_op  DOWN
  247. $ BD0F    $ 6B00    special_op    -ROT        \ these are synonyms
  248. $ BD0F    $ 6C00    special_op    2SWAP
  249.  
  250. \ FP stack ops:
  251.  
  252. $ BD0F    $ 7200    special_op  FDUP
  253. $ BD0F    $ 7300    special_op  F2DUP
  254. $ BD0F    $ 7400    special_op  FDROP
  255. $ BD0F    $ 7500    special_op  F2DROP
  256. $ BD0F    $ 7600    special_op  FSWAP
  257. $ BD0F    $ 7700    special_op  FOVER
  258. $ BD0F    $ 7800    special_op  FNIP
  259. $ BD0F    $ 7900    special_op  FTUCK
  260. $ BD0F    $ 7A00    special_op  FROT
  261. $ BD0F    $ 7B00    special_op  FDOWN
  262. $ BD0F    $ 7C00    special_op    F2SWAP
  263.  
  264.  
  265. \ I use the following in inline code sequences here in the nucleus, before
  266. \  locals are avaliable.  And they're also handy in inlines.
  267.  
  268. $ BD0F    $ 6D00    special_op    2PICK
  269. $ BD0F    $ 6E00    special_op    3PICK
  270. $ BD0F    $ 6F00    special_op    3ROLL
  271.  
  272.  
  273. :ppc_code PICK
  274.     r4    0            cmpi,        \ is it 0 pick?
  275. eq if,
  276.     r4    r3 r3        or,            \ yes - copy TOS
  277. else,
  278.     r5    r4 2 0 29    rlwinm,        \ no - mult index by 4
  279.     r5    r5 -4        addi,        \  and subtract 4 to get SP offset
  280.     r4    r18 r5        lwzx,        \ grab the cell
  281. then,
  282.  
  283.                     blr,        \ and return.
  284. ;ppc_code
  285.  
  286.  
  287. \                =============================
  288. \                     SIMPLE ARITHMETIC
  289. \                =============================
  290.  
  291.  
  292. $ BD06    otAdd    special_op  +
  293. $ BD06    otSub    special_op  -
  294. $ BD06    otMul    special_op    *
  295. $ BD06    otMul    special_op    *W        \ don't need this as a separate op on PPC
  296. $ BD06    otMulh    special_op    *HI        \ will normally only be used internally
  297. $ BD06    otUMulh    special_op    *UHI    \ ditto
  298. $ BD06    otDiv    special_op    /
  299. $ BD06    otUDiv    special_op    U/
  300.  
  301. : M*   ( n1 n2 -- d )    inline{ 2dup * down *hi}  ;
  302. : UM*  ( u1 u2 -- ud )    inline{ 2dup * down *uhi} ;
  303.  
  304. \ we need um* - the standard sez so!!
  305.  
  306. \ Special arith ops to get us specific instructions, mainly for use
  307. \  in inline sequences.  We leave it as an exercise for the reader 
  308. \  to work out what the instructions are.
  309.  
  310. $ BD06    otAddc        special_op    __addc
  311. $ BD06    otAdde        special_op    __adde
  312. $ BD06    otAddze        special_op    __addze
  313. $ BD06    otSubfc        special_op    __subfc
  314. $ BD06    otSubfe        special_op    __subfe
  315. $ BD06    otSubfze    special_op    __subfze
  316.  
  317.  
  318. \ NEGATE and DNEGATE.  The latter can be done with the special ops we just
  319. \  defined.
  320.  
  321. $ BD06    otNEG    special_op  NEGATE
  322.  
  323. : DNEGATE    inline{ swap 0 __subfc swap __subfze}  ;
  324.  
  325. \ We need D+ in number input, so we might as well put D- here as well.
  326. \ These sequences do the job in 2 or 3 instructions.
  327.  
  328. : D+  ( d1 d2 -- d3 )
  329.      inline{ swap 3roll __addc down __adde}  ;
  330.  
  331.  
  332. : D-  ( d1 d2 -- d3 )
  333.     inline{ swap 3roll swap __subfc down __subfe}  ;
  334.  
  335.  
  336. \ FP:
  337.  
  338. $ BD06    otFADD    special_op    F+
  339. $ BD06    otFSUB    special_op    F-
  340. $ BD06    otFMUL    special_op    F*
  341. $ BD06    otFDIV    special_op    F/
  342.  
  343. $ BD06    $ 54    special_op    FABS
  344. $ BD06    $ 55    special_op    FNEGATE
  345.  
  346.  
  347. \ Shifts:
  348.  
  349. $ BD30    $ 2A00    special_op  <<
  350. $ BD30    $ 2A00    special_op  LSHIFT
  351. $ BD30    $ 2A01    special_op  >>
  352. $ BD30    $ 2A01    special_op  RSHIFT
  353. $ BD30    $ 2A03    special_op  A>>
  354.  
  355.  
  356. \ the following inline definitions use some ops like > which we haven't
  357. \  defined in the nucleus image yet.  But since inlines use EVALUATE,
  358. \  as long as the ops are defined somewhere in the nucleus there should
  359. \  be no problem, since we precompile the nucleus.
  360.  
  361. : 2*    inline{ dup +}  ;
  362. : 4*    inline{ 2 <<}    ;
  363.  
  364. : 2/    inline{ 1 a>>}  ;
  365. : 4/    inline{ 2 a>>}    ;
  366.  
  367. : UNDER+    \ ( a b c -- a+c b )
  368.         inline{ rot + swap}  ;
  369.  
  370. : MAX    inline{ 2dup >= dup not rot and down and or}  ;
  371. : MIN    inline{ 2dup < dup not rot and down and or}  ;
  372.                 \ we use >= instead of > for MAX, since this gives one
  373.                 \  less instruction in the case 0 MAX.  But for MIN,
  374.                 \  using < gives TWO less instructions than <= (just 2)
  375.  
  376. : UMAX    inline{ 2dup u> dup not rot and down and or}  ;
  377. : UMIN    inline{ 2dup u< dup not rot and down and or}  ;
  378.                 \ Here u>/u< gives one less instruction than
  379.                 \  u>=/u<=.
  380.  
  381. : ABS    inline{ dup 31 a>> tuck + xor}  ;    \ yep, it works!!
  382.  
  383. \ +- ( n1 n2 -- n3 )  negates n1 if n2 is negative.  I like this name
  384. \  better than ?negate, since n2 isn't a flag.  Note that ABS is
  385. \  equivalent to DUP +-.
  386.  
  387. : +-    inline{ 31 a>> tuck + xor}  ;
  388.  
  389.  
  390. : #ALIGN4    inline{ 3+ -4 and}  ;    \ other alignment words are in pnuc3,
  391.                                     \  but we need this one earlier.
  392.  
  393. : EXTEND    inline{ 16 << 16 a>>}  ;
  394. : S>D        inline{ dup 31 a>>}  ;
  395.  
  396.  
  397.  
  398. \                =============================
  399. \                      LOGICAL OPERATIONS
  400. \                =============================
  401.  
  402.  
  403. \ NOT and INVERT are synonyms.
  404.  
  405. $ BD06    otNOT    special_op  NOT
  406. $ BD06    otNOT    special_op  INVERT
  407.  
  408. $ BD06    otAND    special_op  AND
  409. $ BD06    otOR    special_op  OR
  410. $ BD06    otXOR    special_op  XOR
  411.  
  412.  
  413. \ Logical operations directly on a memory byte.  We define these as inlines,
  414. \  since the'll only generate a few instructions.
  415.  
  416. : CSET      \ ( c addr -- )  ORs c into the byte at addr.
  417.  
  418.     inline{ dup c@ rot or swap c!}  ;
  419.  
  420. : CRESET    \ ( c addr -- )  clears bits in byte at addr, corresponding
  421.             \ to the bits SET in c.    
  422.             
  423.     inline{ dup c@ rot not and swap c!}  ;
  424.  
  425. : CTOGGLE    \ ( c addr -- )  Exclusive-ORs c into the byte at addr.
  426.  
  427.     inline{ dup c@ rot xor swap c!}  ;
  428.  
  429.  
  430. : CREPLACE    \ ( c mask addr -- )
  431.             \ Replaces bits in the addressed byte with the corresponding
  432.             \ bits from c, in those positions where the mask has ones.
  433.  
  434.     inline{ 2dup c@ swap not and 2swap and or swap c!}  ;
  435.  
  436. (*
  437. : CREPLACE  { c mask addr -- }
  438.     addr c@  mask not and  c mask and  or  addr c!  ;
  439. *)
  440.  
  441. \ Logical operations on a memory bit - now omitted.  Almost unused.
  442.  
  443.  
  444. \            ===========================
  445. \                    COMPARISONS
  446. \            ===========================
  447.  
  448.  
  449. $ BD10    $ 2607    special_op  =
  450. $ BD10    $ 2606    special_op  <>
  451. $ BD10    $ 260C    special_op  >=
  452. $ BD10    $ 260D    special_op  <
  453. $ BD10    $ 260F    special_op  <=
  454. $ BD10    $ 260E    special_op  >
  455.  
  456. $ BD10    $ 2605    special_op  U<
  457. $ BD10    $ 2603    special_op  U<=
  458. $ BD10    $ 2602    special_op  U>
  459. $ BD10    $ 2604    special_op  U>=
  460.  
  461. $ BD10    $ 2617    special_op  0=
  462. $ BD10    $ 2616    special_op  0<>
  463. $ BD10    $ 261C    special_op  0>=
  464. $ BD10    $ 261D    special_op  0<
  465. $ BD10    $ 261F    special_op  0<=
  466. $ BD10    $ 261E    special_op  0>
  467.  
  468. $ BD2A    cmpEQ    special_op  F=
  469. $ BD2A    cmpNE    special_op  F<>
  470. $ BD2A    cmpGE    special_op  F>=
  471. $ BD2A    cmpLT    special_op  F<
  472. $ BD2A    cmpLE    special_op  F<=
  473. $ BD2A    cmpGT    special_op  F>
  474.  
  475. \ FP:
  476.  
  477. $ BD2A    cmpZEQ    special_op  F0=
  478. $ BD2A    cmpZNE    special_op  F0<>
  479. $ BD2A    cmpZGE    special_op  F0>=
  480. $ BD2A    cmpZLT    special_op  F0<
  481. $ BD2A    cmpZLE    special_op  F0<=
  482. $ BD2A    cmpZGT    special_op  F0>
  483.  
  484.  
  485. : WITHIN?    \ ( n lo hi -- n b )  Returns true if  lo <= n <= hi.
  486.  
  487.             \ We define it inline which involves a lot of stack juggling,
  488.             \ but all that gets taken out at compile time, so the compiled
  489.             \ code is actually optimum.
  490.  
  491.     inline{ rot tuck >= down tuck <= rot and}  ;
  492.  
  493. (* that surely needs an explanation:
  494.     rot                    ( lo hi n )
  495.     tuck                ( lo n hi n )
  496.     >= down                ( b lo n )
  497.     tuck                ( b n lo n )
  498.     <=                    ( b n b' )
  499.     rot and
  500. *)
  501.  
  502. : UWITHIN?    \ ( u lo hi -- u b )  An unsigned version of WITHIN?
  503.     inline{ rot tuck u>= down tuck u<= rot and}  ;
  504.  
  505.  
  506. \            ===========================
  507. \                FETCHES AND STORES
  508. \            ===========================
  509.  
  510.  
  511. $ 6102    0    fetch_op    @
  512. $ 6102    0    fetch_op    >PTR        \ In our system, this is an alias for @.
  513.  
  514. $ 6101    0    fetch_op    W@
  515. $ 6101    1    fetch_op    W@X
  516. $ 6100    0    fetch_op    C@
  517. $ 6100    1    fetch_op    C@X
  518.  
  519. $ BD32        simple_op    F@
  520. $ BD33        simple_op    F!
  521. $ BD42        simple_op    SF@
  522. $ BD43        simple_op    SF!
  523.  
  524. $ BD08    $ 6002    special_op    !
  525. $ BD08    $ 2102    special_op    +!
  526. $ BD08    $ 2202    special_op    -!
  527. $ BD08    $ 6001    special_op    W!
  528. $ BD08    $ 2101    special_op    W+!
  529. $ BD08    $ 2201    special_op    W-!
  530. $ BD08    $ 6000    special_op    C!
  531.  
  532.  
  533.  
  534. \            ============================================
  535. \                DO LOOPS and RETURN STACK OPERATIONS
  536. \            ============================================
  537.  
  538. (* Note:  >R, R> and R@ are defined already (at the start of Setup, since
  539.  I needed >R so it was logical to put them all there).
  540.  
  541.  We keep the loop index I in a reg, but the return stack is entirely
  542.  in memory, except that in leaf words we don't save/restore the link
  543.  register.  This means that I can be used in words called from within
  544.  DO loops.  In fact I can be used as another local variable.  But this
  545.  is non-standard, so not a good idea.  But it's useful for testing.
  546.  
  547.  During DO loops, the info for any containing DO loop is saved on the
  548.  return stack in the order I (on top), limit, count register.  Thus
  549.  J is at offset zero off r17 (rtn stk ptr), and K is at offset 12.
  550. *)
  551.  
  552. I_reg        gpr  I
  553.  
  554. : J        inline{ RP @}  ;
  555.  
  556. : K        inline{ RP 8 + @}  ;
  557.  
  558.  
  559. \                    =========================
  560. \                        OBJECT ADDRESSING
  561. \                    =========================
  562.  
  563. (*
  564.   ^BASE and SELF give the base address of the current object.  There are two
  565.   words because "base address of the current object" can have two meanings, thanks
  566.   to multiple inheritance.  ^BASE give what we might call the local base - the
  567.   base address of the current object considered as an object of the class in which
  568.   the ^BASE appears or from which it is called.  In other words, this is the
  569.   address of the first ivar of the class in which the current method is declared.
  570.   Note that all ivars of this class will be at fixed offsets from ^BASE.
  571.   However with multiple inheritance, these ivars might be preceded by ivars of
  572.   a different (inherited) class.  SELF simply the base address of the current
  573.   (dynamic) object, that is, the address of the first ivar (regardless of which
  574.   class it's inherited from).  SELF and ^BASE might give identical results, but
  575.    if they differ, SELF must be lower.
  576.  
  577.   Compiled code in methods needs to access ivars using ^BASE, since the offsets
  578.   are fixed.  The offset from SELF of a given ivar might be different in different
  579.   objects.  For this reason we keep ^BASE in a machine register, but compute SELF.
  580.  
  581. *)
  582.  
  583. \ obj_base_reg    reg    ^BASE
  584.  
  585. : SELF  ( -- addr )
  586.             \ Returns the "real" base addr of the current object.
  587.  
  588.     (^base) 4- dup w@x +        \ ^class addr
  589.     8 +  ;                        \ forward to beginning of obj data
  590.  
  591.  
  592. \                    =========================
  593. \                        SEGMENT HANDLING
  594. \                    =========================
  595.  
  596. (*
  597.     A segment table (ST) entry is 8 bytes long:
  598.     
  599.     byte  0            flags
  600.     bytes 1-3        length of segment
  601.     bytes 4-7        base addr
  602.  
  603.     A free segment is marked by bytes 0-3 being all zero.  Currently
  604.     we don't have such a thing as a zero-length segment, though if
  605.     this ever became useful we could define a flag bit to mean a
  606.     segment isn't free, so that bytes 0-3 being all zero would still
  607.     mean the seg is free.
  608.  
  609.     Note that 2^^24 is more than adequate for a maximum length, so
  610.     there's no problem with using the hi byte for flags.
  611.     
  612.     The maximum number of available ST slots is max_segs.  We number
  613.     segments from 8 up, corresponding to the hi byte of relocatable
  614.     addresses.  Thus the highest legal seg# is max_segs + 7.
  615.     (Offsetting the seg# in this way makes handling reloc addrs 
  616.     slightly easier, and also means that zero is illegal as a reloc
  617.     addr - probably a good idea.)
  618. *)
  619.  
  620. : get_free_seg_pair  { \ ^entry -- ^entry n }
  621.     max_segs 2
  622.     DO    i  8 *  segTable +  -> ^entry
  623.         ^entry @  ^entry 8 + @  or
  624.         NIF                        \ found the first free even-odd pair
  625.             1 ^entry !            \ give them a dummy length of 1 so we can see
  626.             1 ^entry 8 + !        \  they're not free
  627.             ^entry  i 8 +  UNLOOP  EXIT
  628.         THEN
  629.     2 +LOOP
  630.     208 die                    \ table full!  Help!!
  631. ;
  632.  
  633. : segTable_entry        \ ( seg# -- ^entry )
  634.     8 - 
  635.     0 max_segs  within?  NIF 207 die  THEN
  636.     8 *  segTable +
  637. ;
  638.  
  639. : make_seg_absent        \ ( seg# -- )
  640.     segTable_entry 4+
  641.     nilP swap !            \ nilP means it's absent.  Note we leave the 
  642.                         \  length alone, since the seg is still assigned
  643.                         \  to somebody.
  644. ;
  645.  
  646. : free_seg                \ ( seg# -- )
  647.     segTable_entry
  648.     0  over !
  649.     nilP swap 4+ !
  650. ;
  651.  
  652.  
  653. : addr>S&D  { addr \ ^entry BA len xx --  seg# displ }
  654.  
  655. \ compMod $ 10000000 u> if dbgr then
  656. \ addr $ 1000 u< if dbgr then
  657.  
  658.     compMod 0<> comp_seg# and
  659.     IF                \ we're compiling a module.  Is it in that module?
  660.         comp_seg# 8 -  8 *  segTable +  -> ^entry
  661.         ^entry @ $ 00ffffff and  -> len
  662.         ^entry 4+ @ -> BA
  663.  
  664.         addr
  665.         BA dup len +
  666.         uwithin?        \ in code area?
  667.         IF                \ yes!
  668.             BA -  comp_seg#  swap  EXIT
  669.         THEN
  670.  
  671.     ^entry 8 + @ $ 00ffffff and  -> len  ^entry 12 + @  -> BA
  672.     ( addr )
  673.         BA dup len +
  674.         uwithin?
  675.         IF
  676.             BA -  comp_seg# 1+ swap  EXIT
  677.         THEN    drop
  678.     THEN
  679.  
  680.     max_segs 0
  681.     DO    i  8 *  segTable +  -> ^entry
  682.         ^entry @ $ 00ffffff and  -> len
  683.         len
  684.         IF                        \ something there
  685.             ^entry 4+ @ -> BA
  686.             BA nilP <>
  687.             IF                    \ seg is present
  688.                 addr
  689.                 BA dup len +  uwithin?
  690.                 IF                \ found!  addr is within this segment
  691.                         BA -
  692.                         i 8 +  swap UNLOOP  EXIT
  693.                 ELSE    drop
  694.                 THEN
  695.             THEN
  696.         THEN
  697.     LOOP
  698.     0  0        \ search failed - return two zeros
  699. ;
  700.  
  701.  
  702.  
  703. \                    =============================
  704. \                    MISCELLANEOUS LOW-LEVEL WORDS
  705. \                    =============================
  706.  
  707.  
  708. \ SP@ should really only be used for stack dumping.  Therefore the
  709. \ main job is to ensure the memory part of the stack is updated to
  710. \ what's in the regs.
  711.  
  712. :ppc_code SP@
  713.  
  714. $ 0100 codeHere 2- w!    \ change flags to specify 1 result in regs.  This
  715.                         \  simplifies things, since this 1 result is just
  716.                         \  the updated data stack pointer.
  717.  
  718.     r3        -4    rSP        stw,
  719.     r4        -8    rSP        stwu,
  720.     r3        rSP            mr,
  721.                         blr,
  722. ;ppc_code
  723.  
  724.  
  725. : SP!    -> SP  ;
  726.  
  727. RP_reg    gpr  RP@        \ synonym for RP in Mops
  728.  
  729. : RP!    0 -> exBuff_offs  -1 -> (^base)
  730.         -> RP  ;
  731.         
  732. : FSP!    -> FSP  ;
  733.  
  734.  
  735. : BOUNDS    inline{ over + swap}  ;
  736.  
  737. : HERE        inline{ dp}  ;
  738.  
  739. : ALLOT        inline{ ++> dp}  ;
  740.  
  741. : ROOM  ( -- n )
  742.     code_limit CDP -  ;
  743.  
  744. : ROOM2  ( -- code-room data-room )
  745.     code_limit CDP -  data_limit DP -  ;
  746.  
  747.     
  748. : HEADROOM  ( -- n )    \ On the 68k, returns the distance from DP to the top of
  749.                         \  the A4 addressing range.  Here on the PPC we make it
  750.                         \  the distance from CDP to the top of the mainCode addressing
  751.                         \  range - that's probably somewhat useful, though the
  752.                         \  distance from DP to the top of the mainData addressing
  753.                         \  range would be useful as well.
  754.     mainCode half_displ_range +  CDP -  ;
  755.  
  756.  
  757. : UNUSED    inline{ room}  ;
  758.  
  759. : COUNT        inline{ dup 1+ swap c@}  ;
  760.  
  761. : LENGTH    inline{ dup 2+ swap w@}  ;
  762.  
  763. : DEPTH
  764.     SP0 SP -  4/  2+  ;            \ we have 2 cells in regs on entry
  765.     
  766. : FDEPTH
  767.     FSP0 FSP -  3 a>>  2+  ;    \ ditto
  768.  
  769.  
  770. : DIGIT  { char #base -- b }
  771.     false
  772.     char  & z  u>    ?EXIT                    \ if above LC letters, fail
  773.     char  & a  u>= IF $ DF and> char THEN    \ LC letter -> UC
  774.     $ 30  --> char                            \ '0'-'9' -> 0-9
  775.     char 0<            ?EXIT                    \ if not a digit, fail
  776.     char 10 >=
  777.     IF    7 --> char                            \ A-Z -> 10-35
  778.         char 10 <    ?EXIT                    \ but if not a letter, fail
  779.     THEN
  780.     char #base >=    ?EXIT                    \ if char now > base, fail
  781.     drop  char true                            \ if we got here, success!
  782. ;
  783.  
  784.  
  785. : DECIMAL    10 -> base  ;
  786. : HEX        16 -> base  ;
  787.  
  788.  
  789. (* HASH produces a 32-bit hash value.  We always set the top bit
  790.   (so that a hashed value is never zero, and is always distinguishable
  791.   from a relocatable address, which is always "positive").
  792.  
  793.   This means that we effectively have 2**31 hash possibilities.  This is
  794.   large enough that hash collisions should hardly ever occur.
  795.   If a 16-bit hash value is required, as in Neon, use wHash.
  796.   
  797.   We use assembly for the inner loop, mainly because we don't yet have
  798.   a good way of specifying a rotate in high-level.  But it's interesting
  799.   that I hardly ever have to resort to assembly for anything any more...
  800. *)
  801.  
  802. :ppc_code (hash)    \ ( addr -- hash )
  803.  
  804.     r5        $ 12345678    lli,
  805.     r5        8            srwi,
  806.  
  807.     r0        0    r4        lbz,
  808.     r0        $ 7F        andi.,
  809.     r0                    mtctr,
  810.     rX        r4    1        addi,
  811.     r4        r0    0        addi,
  812. begin,
  813.     r4        r4 7 0 31    rlwinm,
  814.     r0        0    rX        lbz,
  815.     rX        1            addi,
  816.     r4        r0            xor,
  817. dnz until,
  818.                         blr,
  819.  
  820. ;ppc_code
  821.  
  822.  
  823. : HASH
  824.     (hash)
  825.     dup 0> IF  not  THEN  ;
  826.  
  827. : WHASH
  828.     (hash)
  829.     dup $ FFFF and
  830.     swap 16 >> xor  ;
  831.  
  832.  
  833. : <^ELEM>  { index \ addr -- addr index }
  834.             \ Returns addr of indexed element in current object.
  835.  
  836. \    (^base) dup 4- w@x +        \ ^class addr
  837. \    dup 6 + w@x +  -> addr        \ indexed base addr
  838. \    index  addr 4- @ u>  ?trap    \ trap if out of range - note we store
  839.                                     \  limit-1 in the object, so equal is OK.
  840.  
  841.     (^base) 2- dup w@x + -> addr    \ indexed area base addr
  842.     index  addr 4- @ u>  ?trap        \ trap if out of range - note we store
  843.                                     \  limit-1 in the object, so equal is OK.
  844.     addr index  ;
  845.  
  846.  
  847. : (^ELEM)
  848.     <^elem>  over 6 - w@  * +  ;    \ compiled by ^ELEM if we're not
  849.                                     \  expanding an inline defn - see
  850.                                     \  qClass.
  851.  
  852. : ^ELEM1    <^elem>  +  ;
  853.  
  854. : ^ELEM2    <^elem>  dup + +  ;
  855. : ^ELEM4    <^elem>  4* +  ;
  856.  
  857.  
  858. : IDXBASE  { \ addr -- addr }
  859.             \ Returns start addr of indexed area in current object.
  860.  
  861. \    (^base) dup 4- w@x +        \ ^class addr
  862. \    dup 2- w@x +  -> addr        \ indexed base addr
  863.  
  864.     (^base) 2- dup w@x + -> addr    \ indexed area base addr
  865.     addr 4- @ 0<  ?trap                \ trap if not indexed
  866.     addr ;
  867.  
  868. : LIMIT
  869.     idxbase 4- @ 1+  ;        \ we store limit-1 in the object
  870.  
  871.  
  872. (*    We still need PACK and UNPACK on the PPC, since the Toolbox
  873.     takes and returns a packed Point in a couple of places.
  874.     Note these numbers are signed.
  875. *)
  876.  
  877. : PACK  ( n1 n2 -- n2:n1 )
  878.     16 <<  swap  $ ffff and  or  ;
  879.  
  880. : UNPACK  ( n2:n1 -- n1 n2 )
  881.     dup  16 << 16 a>>  swap  16 a>>  ;
  882.  
  883.  
  884.  
  885. (*    Extra multiplication and division words.
  886.     On the 68k, we dispensed with all double length (64-bit) arithmetic 
  887.     in the nucleus, since the hardware didn't provide it.  We used a kludged
  888.     version of I/O words such as #, in which we just ignored the high
  889.     word.  We required loading of an extra file (longMath) if the real 
  890.     64-bit words were needed.  However here we do provide a few 64-bit 
  891.     words since 32*32->64 is easy, and the Compiler Writers' Guide has
  892.     given us a 64/64->64 division routine.  This means that we don't have
  893.     to kludge # et al, and don't need a PowerPC version of longMath.
  894. *)
  895.  
  896. : /MOD    inline{ 2dup / -> rX rX * - rX}  ;
  897.                     \ tried assembly, but the code compiled by this was
  898.                     \  identical, except for reg numbers  :-)
  899.  
  900. : U/MOD    inline{ 2dup u/ -> rX rX * - rX}  ;
  901.  
  902. : MOD    inline{ /mod drop}  ;
  903.  
  904.  
  905.  
  906. (*    64-bit division on 32-bit PowerPC implementations isn't easy, since
  907.     they took away the MQ register, and left us with only 32/32->32
  908.     instructions.
  909.     
  910.     But fortunately the Compiler Writer's Guide tells us how to do
  911.     64/64->64, so here we go...
  912. *)
  913.  
  914.  
  915. :ppc_code UD/MOD  ( ud_dvd ud_dsr -- ud_rem ud_quot )
  916.  
  917. (*    On entry: divisor = r4:r3, dividend in 0(rSP):4(rSP), and
  918.     we move it to r6:r5.
  919.     We use tmp = r8:r7.  r0 and r10 are scratch.
  920.     
  921.     Note the dividend is only 64 bits, instead of the 128 that 
  922.     would normally go with a 64 bit divisor.  We assume the high
  923.     64 bits are zero.  This means that no divisor/dividend 
  924.     combinations can overflow, unless the divisor is zero.
  925.  
  926.     Note also we put the most significant cell second in the
  927.     registers, because that's the way the regs get passed in to us 
  928.     and the way we need to return them, and it's less confusing 
  929.     to be consistent all the way through - once we get over
  930.     the confusion of having the registers this way around.
  931. *)
  932.  
  933. \ first we check for zero divisor
  934.  
  935.     r0        r3    r4        or.,
  936. ne if,
  937.  
  938.     r6        0    rSP        lwz,        \ get dividend to r6:r5
  939.     r5        4    rSP        lwz,
  940.  
  941. \ first we count the leading zeros in the dividend -> r0
  942.  
  943.     r6        0            cmpi,        \ dvd(hi) = 0?
  944.     r0        r6            cntlzw,        \ r0 = LZ in dvd(hi)
  945.     r9        r5            cntlzw,        \ r9 = LZ in dvd(lo)
  946. eq if,                                \ if dvd(hi) = 0
  947.     r0        r9    32        addi,        \   LZ = LZ(lo) + 32
  948. then,
  949.  
  950. \ now we count the leading zeros in the divisor -> r9
  951.  
  952.     r4        0            cmpi,        \ dsr(hi) = 0?
  953.     r9        r4            cntlzw,        \ r9 = LZ in dsr(hi)
  954.     r10        r3            cntlzw,        \ r10 = LZ in dsr(lo)
  955. eq if,                                \ if dsr(hi) = 0
  956.     r9        r10    32        addi,        \   LZ = LZ(lo) + 32
  957. then,
  958.  
  959. \ now we work out the shift amounts to minimize the number of
  960. \  iterations.
  961.  
  962.     r0        r9            cmp,        \ compare dvd LZ to dsr LZ
  963.     r10        r0    64        subfic,        \ r10 = dividend sig digits (SD)
  964. le if,                                \ if divisor > dividend we keep going,
  965.                                     \  otherwise we set quotient to 0
  966.     r9        r9    1        addi,
  967.     r9        r9    64        subfic,        \ r9 = divisor SD
  968.     r0        r0    r9        add,        \ r0 =  dvd LZ + dsr SD, i.e. left shift
  969.                                     \  of dvd for initial tmp
  970.     r9        r9    r10        subf,        \ r9 = dvd SD - dsr SD i.e. right shift
  971.                                     \  of dividend for initial temp
  972.     r9                    mtctr,        \ ..which is also the number of iterations.
  973.  
  974. \ now we set up r8:r7:r6:r5 as the classic division register whose length
  975. \  is the sum of the quotient and remainder lengths - in our case, 128 bits.
  976. \  First, the hi-order part (r8:r7) is the dividend, right shifted by r9
  977. \  (the number of iterations).
  978.  
  979.     r9        32            cmpi,        \ r9 ? 32
  980.     r8        r9    -32        addi,
  981. ge if,                                \ r9 >= 32:
  982.     r7        r6    r8        srw,        \    lo word = dvd(hi) >> (r9-32)
  983.     r8        0            li,            \   hi word = 0
  984. else,                                \ r9 < 32:
  985.     r7        r5    r9        srw,        \    lo word = dvd(lo) >> r9
  986.     r8        r9    32        subfic,
  987.     r8        r6    r8        slw,        \    r8 = dvd(hi) << (32-r9)
  988.     r7        r7    r8        or,            \     OR that into lo word
  989.     r8        r6    r9        srw,        \    hi word = dvd(hi) >> r9
  990. then,
  991.  
  992. \ Now the lo-order part of the division register (r6:r5) is the
  993. \  dividend left shifted by r0.
  994.  
  995.     r0        32            cmpi,        \ r0 ? 32
  996.     r9        r0    -32        addic,
  997. ge if,                                \ r0 >= 32:
  998.     r6        r5    r9        slw,        \   hi word = dvd(lo) << (r0-32)
  999.     r5        0            li,            \    lo word = 0
  1000. else,                                \ r0 < 32:
  1001.     r6        r6    r0        slw,        \    hi word = dvd(hi) << r0
  1002.     r9        r0    32        subfic,
  1003.     r9        r5    r9        srw,        \    r9 = dvd(lo) >> (r0-32)
  1004.     r6        r6    r9        or,            \    OR that into hi word
  1005.     r5        r5    r0        slw,        \    lo word = dvd(lo) << r0
  1006. then,
  1007.  
  1008. \ Now for the main restoring division shift and subtract loop.
  1009. \ With each shift we subtract the divisor from the top half of
  1010. \  the 128-bit "register", but only use the result if it's positive.
  1011. \ In this case we shift in a 1 into the low bit position.  Otherwise
  1012. \  we shift in a 0.  This will be the next bit of the quotient.
  1013. \ At the end of the loop, we'll have the remainder in the high
  1014. \  half, and the quotient in the low half.
  1015.  
  1016.     r10        -1            li,            \ r10 = -1 for carry setting
  1017.     r8        r8    0        addic,        \ clear carry initially
  1018.  
  1019. CDPx                                    \ loop start
  1020.     r5        r5    r5        adde,        \ here we shift the long register
  1021.     r6        r6    r6        adde,        \  left one place by adding each
  1022.     r7        r7    r7        adde,        \  portion to itself, with carry
  1023.     r8        r8    r8        adde,
  1024.     r0        r3    r7        subfc,        \ Subtract divisor from hi half
  1025.     r9        r4    r8        subfe.,        \  of long register -> r9:r0
  1026.  ge if,                                \ Result was positive, so we use it
  1027.     r7        r0            mr,            \ move result to hi half of long reg
  1028.     r8        r9            mr,
  1029.     r0        r10    1        addic,        \ and set carry bit -
  1030.  then,                                \ carry bit will come into the lo
  1031.                                      \  bit position of the long reg on
  1032.                                      \  the next shift.
  1033.  
  1034. dnz bc,                                \ loop
  1035.  
  1036. \ now we write the results.  The quotient is in the lo half of the long
  1037. \  reg, but needs one more shift, bringing the carry into the lo bit.
  1038. \ At the same time we get the quotient to r4:r3, where we want it.
  1039.  
  1040.     r3        r5    r5        adde,        
  1041.     r4        r6    r6        adde,
  1042.  
  1043. \ The remainder is in r8:r7 - we now put it back into the memory part
  1044. \  of the stack, where the original dividend came from.  As we always
  1045. \  return 2 cells in registers from a code definition, we'll now
  1046. \  have the remainder under the quotient, as required.
  1047.  
  1048.     r7        4    rSP        stw,
  1049.     r8        0    rSP        stw,
  1050.  
  1051.                         blr,
  1052. then,
  1053.  
  1054. \ if we got here, the divisor > dividend, so the quotient is zero
  1055. \  and remainder = dividend.  The remainder is already in the right
  1056. \  place so we only have to clear the quotient (r4:r3).
  1057.  
  1058.     r3        0            li,
  1059.     r4        0            li,
  1060.                         blr,
  1061.  
  1062. then,
  1063.  
  1064. \ and if we got here, the divisor was zero.  We THROW the code -10, which
  1065. \  means "division by zero".
  1066.  
  1067.     r4        -10            li,
  1068.     r0        ' throw 2+    dicaddr,
  1069.     r0                    mtctr,
  1070.                         bctr,
  1071. ;ppc_code
  1072.  
  1073.  
  1074. : UM/MOD  ( d u -- urem uquot )
  1075.     0  ud/mod  drop nip  ;
  1076.  
  1077.  
  1078. : UMD/MOD  ( ud_dvd u_dsr -- u_rem ud_quot )
  1079.     0  ud/mod  rot drop  ;
  1080.  
  1081.  
  1082. : M/MOD  ( d n ) { \ dvdSgn dsrSgn -- rem quot }
  1083.     false -> dvdSgn
  1084.     s>d  dup -> dsrSgn  tuck + xor
  1085.     over 0< IF  down dnegate rot  true -> dvdSgn  THEN
  1086.     um/mod
  1087.  
  1088. \ now we set the sign of the quotient - negative if the
  1089. \  signs of the dividend and divisor differed.
  1090.  
  1091.     dvdSgn dsrSgn xor tuck + xor
  1092.  
  1093. \ now we set the sign of the remainder - same as dividend.
  1094.  
  1095.     swap dvdSgn tuck + xor  swap
  1096. ;
  1097.  
  1098.  
  1099. : */MOD        inline{ -> rY m* rY m/mod}  ;
  1100.  
  1101. : */        inline{ */mod nip}  ;
  1102.  
  1103.